/** \file construct.c
 *
 * Auxiliary functions to construct assembly code for emulation
 *
 * (c) 11/2004 Martin Strubel <hackfin@section5.ch>
 *
 * $Id: construct.c 26 2005-05-24 15:15:02Z philwil $
 *
 */

#include "construct.h"
#include "bfin-registers.h"

#include <stdio.h>

OPCODE32
cons_ldimm(int regno, int high, unsigned long addr)
{
	OPCODE32 ldi = 0xe1000000;
	
	if (regno >= T_REG_A) {
		printf("Error: Wrong register number\n");
		return 0;
	}

	ldi |= (regno & 7) << 16 ;
	ldi |= GROUP(regno) << 19;

	if (high) {
		addr >>= 16;
		ldi |=  1 << 22;   // select high word
	}
	ldi |= addr & 0xffff;

	return ldi;
}

OPCODE32
cons_ldstidxi(int ptr, int data, long offset, int size, int write)
{
	OPCODE32 stidx = 0xe4000000;

	stidx |= (write & 1) << 25; // write flag
	stidx |= (size & 3) << 22;

	stidx |= (ptr & 7) << 19;
	stidx |= (data & 7) << 16;

	switch (size) {
		case LDST_32:
			offset >>= 2; break;
		case LDST_16:
			offset >>= 1; break;
		default:
			break;
	}
	if (!(offset < 32767 && offset > -32768)) {
		printf("Warning: offset out of range\n");
	}
	stidx |= offset & 0xffff;

	return stidx;
}

OPCODE32
cons_ldst(int ptr, int data, int size, int write)
{
	OPCODE32 ld = 0x90000000;

	ld |= (ptr & 7) << 19;
	ld |= (data & 7) << 16;
	ld |= (size & 3) << 26;
	ld |= (write & 1) << 25;

	return ld;
}


OPCODE32
cons_regmv(int dst, int src)
{
	OPCODE32 mv = 0x30000000;

	mv |= (src & 7) << 16; mv |= GROUP(src) << 22;
	mv |= (dst & 7) << 19; mv |= GROUP(dst) << 25;

	return mv;
}

